from google.appengine.ext import db
from app.helpers.simplify import simplify
import re

class Name(object):
  """ Represents a surname, given_name combination
  
  Allows for very loose comparison, ignoring case, space, order, etc.
  We do this because we're dealing with volunteers entering in lots of
  data that's probably all formatted incorrectly
  
  >>> name = Name.make_from_str('Erica Delacruz')
  
  >>> assert name == Name.make_from_str('Delacruz, Erica')
  >>> assert name == Name.make_from_str('Erica De La Cruz')
  >>> assert name == 'erica delacruz   '
  >>> assert name == u'Erica@De_La_Cruz!'
  
  You do need all the words though
  
  >>> assert name != 'Erica Cruz'
  >>> assert name != 'De La Cruz'
  >>> assert name != None
  
  """
  def __init__(self, surname='', given_name=''):
    self.surname = surname
    self.given_name = given_name
  
  def __str__(self):
    return '%s, %s' % (self.surname, self.given_name)
  
  def __repr__(self):
    return 'Name(%s)' % str(self)
  
  def __eq__(self, x):
    if not x:
      return False
    
    if not isinstance(x, Name):
      x = Name.make_from_str(x)
    
    x1 = simplify(x.given_name + x.surname)
    x2 = simplify(x.surname + x.given_name)
    s1 = simplify(self.given_name + self.surname)
    s2 = simplify(self.surname + self.given_name)
    
    return (x1 == s1 or x1 == s2 or x2 == s1 or x2 == s2)
  
  def __ne__(self, x):
    return not self.__eq__(x)
  
  @classmethod
  def make_from_string(cls, string):
    """ Makes Name object from string """
    if ',' in string: # Using Last Name, First Name notation
      split = string.split(',')
      surname = split[0].strip()
      given_name = ','.join(split[1:]).strip()
    
    else: # Using FirstName LastName notation
      split = string.split(' ')
      surname = split[-1].strip()
      given_name = ' '.join(split[:-1])
    
    return cls(surname, given_name)
  
  make_from_str = make_from_string

class NameProperty(db.Property):
  """ Property for storing a name
  
  More complex than a simple string since people have first names,
  last names, middle names, all in various orders
  
  """
  data_type = Name
  
  verbose_type = 'Surname, Given Name'
  
  def get_value_for_datastore(self, model_instance):
    value = super(NameProperty, self).get_value_for_datastore(model_instance)
    if isinstance(value, Name):
      return [value.surname, value.given_name]
    
  def get_value_for_lookup(self, model_instance):
    value = self.get_value_for_datastore(model_instance)
    if value:
      surname, given_name = value
      return [surname, given_name,
        '%s %s' % (surname, given_name),
        '%s %s' % (given_name, surname),
        '%s,%s' % (surname, given_name)]
  
  def get_value_for_sort(self, model_instance):
    return self.get_value_for_datastore(model_instance)
  
  def validate(self, value):
    if not value:
      return None
    if isinstance(value, tuple) or isinstance(value, list):
      return Name(*value)
    if isinstance(value, basestring):
      return Name.make_from_string(value)
    return value
  
  def make_value_from_datastore(self, value):
    if value is None:
      return None
    if hasattr(value, '__iter__'):
      return Name(*value)
    return value
